import Taro from "@tarojs/taro";
import { baseURL } from "@/utils/constant"


type IOption<T, P> = {
  url: string,
  data?: T,
  header?: Record<string, string>,
  params?: P
}

const interceptor = (chain: Taro.Chain) => {
  const requestParams = chain.requestParams;
  const token = Taro.getStorageSync("token");
  requestParams.header = {
    ...requestParams.header,
    Authorization: 'Bearer ' + token
  }
  return chain.proceed(requestParams).then(res => res)
}

Taro.addInterceptor(interceptor);

type Method = "GET" | "POST" | "DELETE" | "PUT" | "PATCH"

class Http {
  private static buildUrl(url: string, params?: Record<string, any>): string {
    if (!params) return url;
    const queryParams = new URLSearchParams(params).toString();
    return `${url}${queryParams}`
  }

  private static async request<T, D, P>(option: IOption<D, P>, method: Method = "GET"): Promise<T> {
    try {
      const url = this.buildUrl(`${baseURL}${option.url}`, option.params!);
      const res = await Taro.request({
        url,
        data: option.data,
        header: {
          "content-type": "application/json",
          ...option.header
        },
        method
      })
      if (res.statusCode >= 200 && res.statusCode < 300) {
        return res.data;
      } else {
        throw new Error(`HTTP error! Status: ${res.statusCode}`);
      }
    } catch (error) {
      throw new Error(`Request failed: ${error}`);
    }
  }

  static async get<T, D = any, P = any>(option: IOption<D, P>): Promise<T> {
    try {
      const response = await this.request<T, D, P>(option, "GET");
      return response;
    } catch (error) {
      throw new Error(`Error fetching data from ${option.url}: ${error}`);
    }
  }

  static async post<T, D = any, P = any>(option: IOption<D, P>): Promise<T> {
    try {
      const response = await this.request<T, D, P>(option, "POST");
      return response;
    } catch (error) {
      throw new Error(`Error posting data to ${option.url}: ${error}`);
    }
  }
}

export default Http;
